#include <windows.h>
#include <map>

#include "multithreading.hpp"

namespace multithreading{

    mutex_map mutexmap;

    event::event()                  { h = CreateEvent(NULL,TRUE,FALSE,NULL);    }
    event::event(const event &e)    { h = e.h;                                  }
    event::~event()                 { CloseHandle(h);                           }
    void event::set()               { SetEvent(h);                              }
    void event::reset()             { ResetEvent(h);                            }
    void event::wait()              { WaitForSingleObject(h,INFINITE);          }
    bool event::isSet(){
        if (WaitForSingleObject(h,0) == WAIT_OBJECT_0){
            return true;
        } else {
            return false;
        }
    }

    mutex::mutex()                  {  h = CreateMutex(NULL,FALSE,NULL);   }
    mutex::mutex(const mutex &m)    {  h = m.h;                            }
    mutex::~mutex()                 {  CloseHandle(h);                     }
    void mutex::lock()              {  WaitForSingleObject(h,INFINITE);    }
    void mutex::unlock()            {  ReleaseMutex(h);                    }

    template<typename T> void lock(T &obj){
        mutex_iterator it = mutexmap.find(&obj);
        if (it == mutexmap.end()){                  //If no mutex exists for the specified object
            mutex *m = new mutex;                   // ->Create one
            m->lock();                              // ->Lock it
            mutexmap.insert(mutex_pair(&obj,m));    // ->And add it to the mutex_map
        } else {                                    //Or else
            it->second->lock();                     // ->Lock the existing one
        }
    }

    template<typename T> void unlock(T &obj){
        mutex_iterator it = mutexmap.find(&obj);
        if (it != mutexmap.end()){   //If a mutex exists for the specified object
            it->second->unlock();    // -> Unlock it
        }
    }

};
